/* 
 * Shuriken is the legal property of its developers. Please refer to the
 * COPYRIGHT file distributed with this
 * source distribution.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

using System;
using System.Text;
using System.Windows;
using System.Windows.Forms;
using System.Collections;
using System.Collections.Generic;
using Shuriken.Core.Store;
using Shuriken.Core.Utils; 

namespace Shuriken.Core.UI
{

    internal class UIManager
    {
        private static UIManager m_defaultInstance;
        private IUIProvider m_UIProvider; 
        private KeyEventArgs m_LastKeyDown;
        private string m_InputBuffer = string.Empty;
        private const int MAXIMUM_SEARCHKEY_LENGTH = 14;

        /// <summary>
        /// Default constructor
        /// </summary>
        UIManager()
        {
            m_UIProvider = new Shuriken.Core.UI.StandardUI.SUIProvider();
            m_UIProvider.RegisterUIManager(this);
        }

        /// <summary>
        /// Gets the default instance of the class 
        /// </summary>
        /// <remarks>
        /// This method is not thread safe. 
        /// </remarks>
        /// <returns>default instance</returns>
        public static UIManager GetDefaultInstance()
        {
            if (m_defaultInstance == null)
            {
                m_defaultInstance = new UIManager();
            }

            return m_defaultInstance;
        }

        /// <summary>
        /// Handles the keydown event from the application 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void UIManager_KeyDown(object sender, KeyEventArgs e)
        {
            Tracer.WriteVerbose(
                "InputForm_KeyDown [" 
                + "KeyCode: " + e.KeyCode.ToString()
                + ",KeyData: " + e.KeyData.ToString()
                + ",KeyValue: " + e.KeyValue.ToString() + "].",
                "UI Manager");

            m_LastKeyDown = e;
        }

        /// <summary>
        /// Handles key press event from the application 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void UIManager_KeyPress(object sender, KeyPressEventArgs e)
        {
            //System.Diagnostics.Debug.Write("UIManager_KeyPress (UIManager.cs) [" + ((int)e.KeyChar).ToString() + "]", "UI");
            //System.Diagnostics.Trace.Write("\n InputForm_KeyPress [");
            //System.Diagnostics.Trace.Write("KeyChar: " + e.KeyChar + "].");

            switch (m_LastKeyDown.KeyCode)
            {
                case Keys.Back:
                    if (!m_UIProvider.IsTextEntryActive)
                    {
                        m_InputBuffer = string.Empty;
                        e.Handled = m_UIProvider.CurrentDisplaySlot.BackKeyPressed();
                    }
                    break;

                case Keys.Enter:
                    m_UIProvider.ShowHideAction(ShowHideReason.EnterKey);

                    List<IUIDisplaySlot> slots = m_UIProvider.GetListOfUISlots();
                    ExecutionHelper.Execute(slots);
                    
                    e.Handled = true;
                    break;

                // Ignoring the keystrokes below
                case Keys.Escape:
                    m_UIProvider.EscapeAction();   
                    e.Handled = true;
                    break;

                // Responding to OemPeriod here because we do not want to add 
                // the period to the input buffer. 
                case Keys.OemPeriod:
                    if (!m_UIProvider.IsTextEntryActive)
                    {
                        m_UIProvider.TextEntryMode(true);
                        e.Handled = true;
                    }
                    break;

                default:
                    if (!m_UIProvider.IsTextEntryActive)
                    {
                        AddToInputBuffer(e.KeyChar);
                    }
                    break;
            }
        }


        /// <summary>
        /// Handling the keys 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void UIManager_KeyUp(object sender, KeyEventArgs e)
        {
            //System.Diagnostics.Trace.Write("\n InputForm_KeyUp [");
            //System.Diagnostics.Trace.Write("KeyCode: " + e.KeyCode.ToString());
            //System.Diagnostics.Trace.Write(", KeyData: " + e.KeyData.ToString());
            //System.Diagnostics.Trace.Write(", KeyValue: " + e.KeyValue.ToString() + "].");

            switch (e.KeyCode)
            {
                case Keys.Up:
                    e.Handled = m_UIProvider.CurrentDisplaySlot.SelectPreviousItemFromDetails();
                    break; 
                case Keys.Down:
                    e.Handled = m_UIProvider.CurrentDisplaySlot.SelectNextItemFromDetails();
                    break; 
                case Keys.Right:
                    e.Handled = m_UIProvider.CurrentDisplaySlot.SelectCurrentItemFromDetails();
                    break;

                case Keys.Tab:
                    //if (e.Shift)
                    //{
                    //    // Shift Tab Pressed 
                    //    System.Diagnostics.Debugger.Break();
                    //}

                    // Tab Only
                    m_UIProvider.TabAction();
                    e.Handled = true;
                    break;
            }
        }

        #region Input Buffer methods

        /// <summary>
        /// Adds a char to input buffer 
        /// </summary>
        /// <param name="letter">char to add</param>
        private void AddToInputBuffer(char letter)
        {
            InputBufferChanged(letter.ToString());
        }

        /// <summary>
        /// Updates the UI to show the input buffer change 
        /// </summary>
        private void InputBufferChanged(string txt)
        {
            if (m_UIProvider.CurrentDisplaySlot.IsInSearchMode)
            {
                SortedDisplayItemList m_SearchResultList;

                m_InputBuffer = m_UIProvider.CurrentDisplaySlot.SearchKey;
                m_InputBuffer += txt.ToUpper();

                // Check if the searchkey is longer than allowed
                if (m_InputBuffer.Length >= MAXIMUM_SEARCHKEY_LENGTH)
                {
                    return; 
                }

                m_UIProvider.CurrentDisplaySlot.SearchKey = m_InputBuffer;

                // lets check out if the current slot has content already
                // if it does then we are going to base our search on the content already there
                // if it was then we search withind the current items only 
                if (m_UIProvider.CurrentDisplaySlot.DisplayItems != null && m_UIProvider.CurrentDisplaySlot.DisplayItems.Count != 0 && m_InputBuffer.Length > 1)
                {
                    m_SearchResultList = m_UIProvider.CurrentDisplaySlot.DisplayItems;
                }
                else
                {
                    // m_SearchResultList = new SortedDisplayItemList();
                    m_SearchResultList = m_UIProvider.CurrentDisplaySlot.InitialDisplayItems;
                }

                // Getting the results from the list only if it has items
                Core.Store.StoreManager.GetDefaultInstance().UpdateListWithSearchTerm(ref m_SearchResultList, m_InputBuffer);

                if (m_SearchResultList.Count > 0)
                {
                    m_UIProvider.CurrentDisplaySlot.UpdateDisplaySlot(m_InputBuffer, 0, m_SearchResultList);
                }
            }
            else
            {
                // Not searching right now. In text mode right now. 
                // Totally ignoring everything and let the control handle all inputs 

                //m_InputBuffer = m_UIProvider.CurrentDisplaySlot.SearchKey;
                //m_InputBuffer += txt;

                //m_UIProvider.CurrentDisplaySlot.SearchKey = m_InputBuffer;
            }
        }

        #endregion


        /// <summary>
        /// ShowHide action 
        /// </summary>
        /// <remarks>
        /// Showing or hiding the UI. If the UI is going to be visible, we are going to do the following: 
        /// Select the first UI slot 
        /// Erase the the buffer. 
        /// </remarks>
        /// <param name="reason">reason for this action</param>
        internal void ShowHideAction(ShowHideReason reason)
        {
            System.Diagnostics.Debug.Assert(m_UIProvider.CurrentDisplaySlot != null, "HotkeyAction found null CurrentDisplaySlot");
            System.Diagnostics.Debug.WriteLine("ShowHideAction (UIManager.cs)", "UI");

            if (!m_UIProvider.IsUIVisible())
            {
                m_UIProvider.ActivateUISlot(0);
            }

            m_UIProvider.ShowHideAction(reason);
        }

        public void ShowNotificationAction(string message)
        {
            Shuriken.WPFUIProvider.WPFProvider notification = new Shuriken.WPFUIProvider.WPFProvider();
            notification.Show(message);            
        }
    }
}
